-#include <errno.h>
#include <fcntl.h>
#include <resolv.h>
#include <signal.h>
#include <uci.h>
#include <uci_blob.h>
-#include <json-c/json.h>
#include <libubox/utils.h>
#include <libubox/avl.h>
#include <libubox/avl-cmp.h>
return ipv6_pxe_entry_new(arch, url) ? -1 : 0;
}
-#define JSON_LENGTH "length"
-#define JSON_PREFIX "prefix"
-#define JSON_SLAAC "slaac"
-#define JSON_TIME "time"
-
-static inline time_t config_time_from_json(time_t json_time)
-{
- time_t ref, now;
-
- ref = time(NULL);
- now = odhcpd_time();
-
- if (now > json_time || ref > json_time)
- return 0;
-
- return json_time + (now - ref);
-}
-
-static inline time_t config_time_to_json(time_t config_time)
-{
- time_t ref, now;
-
- ref = time(NULL);
- now = odhcpd_time();
-
- return config_time + (ref - now);
-}
-
-static inline bool config_ra_pio_enabled(struct interface *iface)
-{
- return config.ra_piofolder_fd >= 0 && iface->ra == MODE_SERVER && !iface->master;
-}
-
-static bool config_ra_pio_time(json_object *slaac_json, time_t *slaac_time)
-{
- time_t pio_json_time, pio_time;
- json_object *time_json;
-
- time_json = json_object_object_get(slaac_json, JSON_TIME);
- if (!time_json)
- return true;
-
- pio_json_time = (time_t) json_object_get_int64(time_json);
- if (!pio_json_time)
- return true;
-
- pio_time = config_time_from_json(pio_json_time);
- if (!pio_time)
- return false;
-
- *slaac_time = pio_time;
-
- return true;
-}
-
-static json_object *config_load_ra_pio_json(struct interface *iface)
-{
- json_object *json;
- int fd;
-
- fd = openat(config.ra_piofolder_fd, iface->ifname, O_RDONLY | O_CLOEXEC);
- if (fd < 0)
- return NULL;
-
- json = json_object_from_fd(fd);
-
- close(fd);
-
- if (!json)
- error("rfc9096: %s: json read error %s",
- iface->ifname,
- json_util_get_last_err());
-
- return json;
-}
-
-void config_load_ra_pio(struct interface *iface)
-{
- json_object *json, *slaac_json;
- struct ra_pio *new_pios;
- size_t pio_cnt;
- time_t now;
-
- if (!config_ra_pio_enabled(iface))
- return;
-
- json = config_load_ra_pio_json(iface);
- if (!json)
- return;
-
- slaac_json = json_object_object_get(json, JSON_SLAAC);
- if (!slaac_json) {
- json_object_put(json);
- return;
- }
-
- now = odhcpd_time();
-
- pio_cnt = json_object_array_length(slaac_json);
- new_pios = realloc(iface->pios, sizeof(struct ra_pio) * pio_cnt);
- if (!new_pios) {
- json_object_put(json);
- return;
- }
-
- iface->pios = new_pios;
- iface->pio_cnt = 0;
- for (size_t i = 0; i < pio_cnt; i++) {
- json_object *cur_pio_json, *length_json, *prefix_json;
- const char *pio_str;
- time_t pio_lt = 0;
- struct ra_pio *pio;
- uint8_t pio_len;
-
- cur_pio_json = json_object_array_get_idx(slaac_json, i);
- if (!cur_pio_json)
- continue;
-
- if (!config_ra_pio_time(cur_pio_json, &pio_lt))
- continue;
-
- length_json = json_object_object_get(cur_pio_json, JSON_LENGTH);
- if (!length_json)
- continue;
-
- prefix_json = json_object_object_get(cur_pio_json, JSON_PREFIX);
- if (!prefix_json)
- continue;
-
- pio_len = (uint8_t) json_object_get_uint64(length_json);
- pio_str = json_object_get_string(prefix_json);
- pio = &iface->pios[iface->pio_cnt];
-
- inet_pton(AF_INET6, pio_str, &pio->prefix);
- pio->length = pio_len;
- pio->lifetime = pio_lt;
- info("rfc9096: %s: load %s/%u (%u)",
- iface->ifname,
- pio_str,
- pio_len,
- ra_pio_lifetime(pio, now));
-
- iface->pio_cnt++;
- }
-
- json_object_put(json);
-
- if (!iface->pio_cnt) {
- free(iface->pios);
- iface->pios = NULL;
- } else if (iface->pio_cnt != pio_cnt) {
- struct ra_pio *tmp;
-
- tmp = realloc(iface->pios, sizeof(struct ra_pio) * iface->pio_cnt);
- if (tmp)
- iface->pios = tmp;
- }
-}
-
-static void config_save_ra_pio_json(struct interface *iface, struct json_object *json)
-{
- size_t tmp_piofile_strlen;
- char *tmp_piofile;
- int fd, ret;
-
- tmp_piofile_strlen = strlen(iface->ifname) + 2;
- tmp_piofile = alloca(tmp_piofile_strlen);
- snprintf(tmp_piofile, tmp_piofile_strlen, ".%s", iface->ifname);
-
- fd = openat(config.ra_piofolder_fd,
- tmp_piofile,
- O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
- 0644);
- if (fd < 0) {
- error("rfc9096: %s: error %m creating temporary json file",
- iface->ifname);
- return;
- }
-
- ret = json_object_to_fd(fd, json, JSON_C_TO_STRING_PLAIN);
- if (ret) {
- error("rfc9096: %s: json write error %s",
- iface->ifname,
- json_util_get_last_err());
- close(fd);
- unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
- return;
- }
-
- ret = fsync(fd);
- if (ret) {
- error("rfc9096: %s: error %m syncing %s",
- iface->ifname,
- tmp_piofile);
- close(fd);
- unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
- return;
- }
-
- ret = close(fd);
- if (ret) {
- error("rfc9096: %s: error %m closing %s",
- iface->ifname,
- tmp_piofile);
- unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
- return;
- }
-
- ret = renameat(config.ra_piofolder_fd,
- tmp_piofile,
- config.ra_piofolder_fd,
- iface->ifname);
- if (ret) {
- error("rfc9096: %s: error %m renaming piofile: %s -> %s",
- iface->ifname,
- tmp_piofile,
- iface->ifname);
- close(fd);
- unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
- return;
- }
-
- iface->pio_update = false;
- warn("rfc9096: %s: piofile updated", iface->ifname);
-}
-
-void config_save_ra_pio(struct interface *iface)
-{
- struct json_object *json, *slaac_json;
- char ipv6_str[INET6_ADDRSTRLEN];
- time_t now;
-
- if (!config_ra_pio_enabled(iface))
- return;
-
- if (!iface->pio_update)
- return;
-
- now = odhcpd_time();
-
- json = json_object_new_object();
- if (!json)
- return;
-
- slaac_json = json_object_new_array_ext(iface->pio_cnt);
- if (!slaac_json) {
- json_object_put(slaac_json);
- return;
- }
-
- json_object_object_add(json, JSON_SLAAC, slaac_json);
-
- for (size_t i = 0; i < iface->pio_cnt; i++) {
- struct json_object *cur_pio_json, *len_json, *pfx_json;
- const struct ra_pio *cur_pio = &iface->pios[i];
-
- if (ra_pio_expired(cur_pio, now))
- continue;
-
- cur_pio_json = json_object_new_object();
- if (!cur_pio_json)
- continue;
-
- inet_ntop(AF_INET6, &cur_pio->prefix, ipv6_str, sizeof(ipv6_str));
-
- pfx_json = json_object_new_string(ipv6_str);
- if (!pfx_json) {
- json_object_put(cur_pio_json);
- continue;
- }
-
- len_json = json_object_new_uint64(cur_pio->length);
- if (!len_json) {
- json_object_put(cur_pio_json);
- json_object_put(pfx_json);
- continue;
- }
-
- json_object_object_add(cur_pio_json, JSON_PREFIX, pfx_json);
- json_object_object_add(cur_pio_json, JSON_LENGTH, len_json);
-
- if (cur_pio->lifetime) {
- struct json_object *time_json;
- time_t pio_lt;
-
- pio_lt = config_time_to_json(cur_pio->lifetime);
-
- time_json = json_object_new_int64(pio_lt);
- if (time_json)
- json_object_object_add(cur_pio_json, JSON_TIME, time_json);
- }
-
- json_object_array_add(slaac_json, cur_pio_json);
- }
-
- config_save_ra_pio_json(iface, json);
-
- json_object_put(json);
-}
-
void odhcpd_reload(void)
{
struct uci_context *uci = uci_alloc_context();
struct lease_cfg *config_find_lease_cfg_by_hostid(const uint64_t hostid);
struct lease_cfg *config_find_lease_cfg_by_ipv4(const struct in_addr ipv4);
int config_set_lease_cfg_from_blobmsg(struct blob_attr *ba);
-void config_load_ra_pio(struct interface *iface);
-void config_save_ra_pio(struct interface *iface);
#ifdef WITH_UBUS
int ubus_init(void);
#include "router.h"
#include "odhcpd.h"
+#include "statefiles.h"
static void forward_router_solicitation(const struct interface *iface);
*
* SPDX-License-Identifier: GPL2.0-only
*/
#include <spawn.h>
#include <libubox/md5.h>
+#include <json-c/json.h>
#include "odhcpd.h"
#include "dhcpv6-ia.h"
renameat(dirfd, ODHCPD_TMP_FILE, dirfd, filename);
}
+#define JSON_LENGTH "length"
+#define JSON_PREFIX "prefix"
+#define JSON_SLAAC "slaac"
+#define JSON_TIME "time"
+
+static inline time_t config_time_from_json(time_t json_time)
+{
+ time_t ref, now;
+
+ ref = time(NULL);
+ now = odhcpd_time();
+
+ if (now > json_time || ref > json_time)
+ return 0;
+
+ return json_time + (now - ref);
+}
+
+static inline time_t config_time_to_json(time_t config_time)
+{
+ time_t ref, now;
+
+ ref = time(NULL);
+ now = odhcpd_time();
+
+ return config_time + (ref - now);
+}
+
+static inline bool config_ra_pio_enabled(struct interface *iface)
+{
+ return config.ra_piofolder_fd >= 0 && iface->ra == MODE_SERVER && !iface->master;
+}
+
+static bool config_ra_pio_time(json_object *slaac_json, time_t *slaac_time)
+{
+ time_t pio_json_time, pio_time;
+ json_object *time_json;
+
+ time_json = json_object_object_get(slaac_json, JSON_TIME);
+ if (!time_json)
+ return true;
+
+ pio_json_time = (time_t) json_object_get_int64(time_json);
+ if (!pio_json_time)
+ return true;
+
+ pio_time = config_time_from_json(pio_json_time);
+ if (!pio_time)
+ return false;
+
+ *slaac_time = pio_time;
+
+ return true;
+}
+
+static json_object *config_load_ra_pio_json(struct interface *iface)
+{
+ json_object *json;
+ int fd;
+
+ fd = openat(config.ra_piofolder_fd, iface->ifname, O_RDONLY | O_CLOEXEC);
+ if (fd < 0)
+ return NULL;
+
+ json = json_object_from_fd(fd);
+
+ close(fd);
+
+ if (!json)
+ error("rfc9096: %s: json read error %s",
+ iface->ifname,
+ json_util_get_last_err());
+
+ return json;
+}
+
+void config_load_ra_pio(struct interface *iface)
+{
+ json_object *json, *slaac_json;
+ struct ra_pio *new_pios;
+ size_t pio_cnt;
+ time_t now;
+
+ if (!config_ra_pio_enabled(iface))
+ return;
+
+ json = config_load_ra_pio_json(iface);
+ if (!json)
+ return;
+
+ slaac_json = json_object_object_get(json, JSON_SLAAC);
+ if (!slaac_json) {
+ json_object_put(json);
+ return;
+ }
+
+ now = odhcpd_time();
+
+ pio_cnt = json_object_array_length(slaac_json);
+ new_pios = realloc(iface->pios, sizeof(struct ra_pio) * pio_cnt);
+ if (!new_pios) {
+ json_object_put(json);
+ return;
+ }
+
+ iface->pios = new_pios;
+ iface->pio_cnt = 0;
+ for (size_t i = 0; i < pio_cnt; i++) {
+ json_object *cur_pio_json, *length_json, *prefix_json;
+ const char *pio_str;
+ time_t pio_lt = 0;
+ struct ra_pio *pio;
+ uint8_t pio_len;
+
+ cur_pio_json = json_object_array_get_idx(slaac_json, i);
+ if (!cur_pio_json)
+ continue;
+
+ if (!config_ra_pio_time(cur_pio_json, &pio_lt))
+ continue;
+
+ length_json = json_object_object_get(cur_pio_json, JSON_LENGTH);
+ if (!length_json)
+ continue;
+
+ prefix_json = json_object_object_get(cur_pio_json, JSON_PREFIX);
+ if (!prefix_json)
+ continue;
+
+ pio_len = (uint8_t) json_object_get_uint64(length_json);
+ pio_str = json_object_get_string(prefix_json);
+ pio = &iface->pios[iface->pio_cnt];
+
+ inet_pton(AF_INET6, pio_str, &pio->prefix);
+ pio->length = pio_len;
+ pio->lifetime = pio_lt;
+ info("rfc9096: %s: load %s/%u (%u)",
+ iface->ifname,
+ pio_str,
+ pio_len,
+ ra_pio_lifetime(pio, now));
+
+ iface->pio_cnt++;
+ }
+
+ json_object_put(json);
+
+ if (!iface->pio_cnt) {
+ free(iface->pios);
+ iface->pios = NULL;
+ } else if (iface->pio_cnt != pio_cnt) {
+ struct ra_pio *tmp;
+
+ tmp = realloc(iface->pios, sizeof(struct ra_pio) * iface->pio_cnt);
+ if (tmp)
+ iface->pios = tmp;
+ }
+}
+
+static void config_save_ra_pio_json(struct interface *iface, struct json_object *json)
+{
+ size_t tmp_piofile_strlen;
+ char *tmp_piofile;
+ int fd, ret;
+
+ tmp_piofile_strlen = strlen(iface->ifname) + 2;
+ tmp_piofile = alloca(tmp_piofile_strlen);
+ snprintf(tmp_piofile, tmp_piofile_strlen, ".%s", iface->ifname);
+
+ fd = openat(config.ra_piofolder_fd,
+ tmp_piofile,
+ O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC,
+ 0644);
+ if (fd < 0) {
+ error("rfc9096: %s: error %m creating temporary json file",
+ iface->ifname);
+ return;
+ }
+
+ ret = json_object_to_fd(fd, json, JSON_C_TO_STRING_PLAIN);
+ if (ret) {
+ error("rfc9096: %s: json write error %s",
+ iface->ifname,
+ json_util_get_last_err());
+ close(fd);
+ unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
+ return;
+ }
+
+ ret = fsync(fd);
+ if (ret) {
+ error("rfc9096: %s: error %m syncing %s",
+ iface->ifname,
+ tmp_piofile);
+ close(fd);
+ unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
+ return;
+ }
+
+ ret = close(fd);
+ if (ret) {
+ error("rfc9096: %s: error %m closing %s",
+ iface->ifname,
+ tmp_piofile);
+ unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
+ return;
+ }
+
+ ret = renameat(config.ra_piofolder_fd,
+ tmp_piofile,
+ config.ra_piofolder_fd,
+ iface->ifname);
+ if (ret) {
+ error("rfc9096: %s: error %m renaming piofile: %s -> %s",
+ iface->ifname,
+ tmp_piofile,
+ iface->ifname);
+ close(fd);
+ unlinkat(config.ra_piofolder_fd, tmp_piofile, 0);
+ return;
+ }
+
+ iface->pio_update = false;
+ warn("rfc9096: %s: piofile updated", iface->ifname);
+}
+
+void config_save_ra_pio(struct interface *iface)
+{
+ struct json_object *json, *slaac_json;
+ char ipv6_str[INET6_ADDRSTRLEN];
+ time_t now;
+
+ if (!config_ra_pio_enabled(iface))
+ return;
+
+ if (!iface->pio_update)
+ return;
+
+ now = odhcpd_time();
+
+ json = json_object_new_object();
+ if (!json)
+ return;
+
+ slaac_json = json_object_new_array_ext(iface->pio_cnt);
+ if (!slaac_json) {
+ json_object_put(slaac_json);
+ return;
+ }
+
+ json_object_object_add(json, JSON_SLAAC, slaac_json);
+
+ for (size_t i = 0; i < iface->pio_cnt; i++) {
+ struct json_object *cur_pio_json, *len_json, *pfx_json;
+ const struct ra_pio *cur_pio = &iface->pios[i];
+
+ if (ra_pio_expired(cur_pio, now))
+ continue;
+
+ cur_pio_json = json_object_new_object();
+ if (!cur_pio_json)
+ continue;
+
+ inet_ntop(AF_INET6, &cur_pio->prefix, ipv6_str, sizeof(ipv6_str));
+
+ pfx_json = json_object_new_string(ipv6_str);
+ if (!pfx_json) {
+ json_object_put(cur_pio_json);
+ continue;
+ }
+
+ len_json = json_object_new_uint64(cur_pio->length);
+ if (!len_json) {
+ json_object_put(cur_pio_json);
+ json_object_put(pfx_json);
+ continue;
+ }
+
+ json_object_object_add(cur_pio_json, JSON_PREFIX, pfx_json);
+ json_object_object_add(cur_pio_json, JSON_LENGTH, len_json);
+
+ if (cur_pio->lifetime) {
+ struct json_object *time_json;
+ time_t pio_lt;
+
+ pio_lt = config_time_to_json(cur_pio->lifetime);
+
+ time_json = json_object_new_int64(pio_lt);
+ if (time_json)
+ json_object_object_add(cur_pio_json, JSON_TIME, time_json);
+ }
+
+ json_object_array_add(slaac_json, cur_pio_json);
+ }
+
+ config_save_ra_pio_json(iface, json);
+
+ json_object_put(json);
+}
+
static void statefiles_write_host(const char *ipbuf, const char *hostname, struct write_ctxt *ctxt)
{
char exp_dn[DNS_MAX_NAME_LEN];
/*
*
* SPDX-License-Identifier: GPL2.0-only
*/
#define ODHCPD_HOSTS_FILE_PREFIX "odhcpd.hosts"
#define ODHCPD_TMP_FILE ".odhcpd.tmp"
+void config_load_ra_pio(struct interface *iface);
+
+void config_save_ra_pio(struct interface *iface);
+
bool statefiles_write(void);
void statefiles_setup_dirfd(const char *path, int *dirfdp);